/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package restClient;

import java.lang.reflect.Type;
import java.util.Map.Entry;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;

import javax.ws.rs.core.MediaType;

import server.ProductStock;
import server.ShoppingCart;
import server.ShoppingCartService;
import server.Stock;

/**
 * This class enables us to use the REST protocol with JSON for our clients.
 *
 * @author Satia Herfert
 */
public class ShoppingCartRestClient implements ShoppingCartService {

	// The URI to use
	public static final String REST_URI = "http://localhost:8080/shoppingCart";

	// All the resources
	private WebResource identifyService;
	private WebResource stockService;
	private WebResource shoppingCartService;
	private WebResource addProductToShoppingCartService;
	private WebResource clearShoppingCartService;
	private WebResource buyService;

	// A GSON Builder
	private GsonBuilder gsonBuilder;

	// Connect using REST
	public ShoppingCartRestClient() {
		ClientConfig config = new DefaultClientConfig();
		Client client = Client.create(config);
		WebResource service = client.resource(REST_URI).path("cart");

		identifyService = service.path("identify");
		stockService = service.path("stock");
		shoppingCartService = service.path("shoppingCart");
		addProductToShoppingCartService = service
				.path("addProductToShoppingCart");
		clearShoppingCartService = service.path("clearShoppingCart");
		buyService = service.path("buy");

		// Register our deserializer for carts/stocks
		gsonBuilder = new GsonBuilder();
		gsonBuilder.registerTypeAdapter(Stock.class, new StockDeserializer());
		gsonBuilder.registerTypeAdapter(ShoppingCart.class,
				new StockDeserializer());
	}

	/**
	 * Used for simple text methods.
	 * 
	 * @param webResource
	 *            the resource
	 * @return retrieve the text content.
	 */
	private String getOutputAsText(WebResource webResource) {
		return webResource.accept(MediaType.TEXT_PLAIN).get(String.class);
	}

	/**
	 * Used for JSON text methods.
	 * 
	 * @param webResource
	 *            the resource
	 * @return retrieve the JSON text content.
	 */
	private String getOutputAsJson(WebResource webResource) {
		return webResource.accept(MediaType.APPLICATION_JSON).get(String.class);
	}

	public long identify(long id) {
		return Long.parseLong(getOutputAsText(identifyService.path("" + id)));
	}

	public void addProductToShoppingCart(long id, long productID) {
		getOutputAsText(addProductToShoppingCartService.path("" + id).path(
				"" + productID));
	}

	public void clearShoppingCart(long id) {
		getOutputAsText(clearShoppingCartService.path("" + id));
	}

	public boolean buy(long id) {
		return Boolean.parseBoolean(getOutputAsText(buyService.path("" + id)));
	}

	public Stock getStock() {
		String stockJson = getOutputAsJson(stockService);
		Gson gson = gsonBuilder.create();
		return gson.fromJson(stockJson, Stock.class);
	}

	public ShoppingCart getShoppingCart(long id) {
		String cartJson = getOutputAsJson(shoppingCartService.path("" + id));
		Gson gson = gsonBuilder.create();
		return gson.fromJson(cartJson, ShoppingCart.class);
	}

	/**
	 * This JSON Deserializer class makes it possible to deserialize JSON
	 * Strings, that have been serialized using the Server model of
	 * ShoppingCart/Stock, into the client model of ShoppingCart/Stock.
	 * 
	 * The models differ, as the client model is generated by wsimport.
	 * 
	 * @author Satia
	 *
	 */
	private class StockDeserializer implements JsonDeserializer<Stock> {
		@Override
		public Stock deserialize(JsonElement json, Type type,
				JsonDeserializationContext context) throws JsonParseException {
			ShoppingCart c = new ShoppingCart();
			ShoppingCart.ActualStock as = new ShoppingCart.ActualStock();
			c.setActualStock(as);

			JsonElement jsonAS = json.getAsJsonObject().get("actualStock");

			for (Entry<String, JsonElement> jsonEntry : jsonAS
					.getAsJsonObject().entrySet()) {
				Long id = Long.parseLong(jsonEntry.getKey());
				ProductStock ps = context.deserialize(jsonEntry.getValue(),
						ProductStock.class);
				Stock.ActualStock.Entry entry = new Stock.ActualStock.Entry();
				entry.setKey(id);
				entry.setValue(ps);
				as.getEntry().add(entry);
			}

			return c;
		}
	}
}
